package cn.iocoder.yudao.module.lowcode.core.script;

import groovy.lang.Binding;
import lombok.Builder;
import lombok.Data;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * Groovy 脚本执行上下文
 * 
 * 封装脚本执行时需要的参数、变量和环境信息
 *
 * @author 芋道源码
 */
@Data
@Builder
public class GroovyScriptExecutionContext {

    /**
     * 脚本参数
     */
    @Builder.Default
    private Map<String, Object> parameters = new HashMap<>();

    /**
     * 系统变量
     */
    @Builder.Default
    private Map<String, Object> systemVariables = new HashMap<>();

    /**
     * 用户上下文信息
     */
    private Long userId;
    private String username;
    private Long tenantId;

    /**
     * 请求上下文信息
     */
    private String requestId;
    private String clientIp;
    private String userAgent;

    /**
     * 数据源映射
     */
    @Builder.Default
    private Map<String, DataSource> dataSources = new HashMap<>();

    /**
     * 创建 Groovy Binding
     */
    public Binding createBinding() {
        Binding binding = new Binding();
        
        // 添加参数 - 两种方式：单个变量 + params对象
        if (parameters != null) {
            // 方式1：每个参数作为单独的变量
            parameters.forEach((key, value) -> {
                binding.setVariable(key, value);
            });
            
            // 方式2：所有参数作为params对象
            binding.setVariable("params", new HashMap<>(parameters));
            
            // 方式3：也提供parameters变量（兼容性）
            binding.setVariable("parameters", new HashMap<>(parameters));
        } else {
            // 即使没有参数，也提供空的params对象
            binding.setVariable("params", new HashMap<>());
            binding.setVariable("parameters", new HashMap<>());
        }
        
        // 添加系统变量
        if (systemVariables != null) {
            systemVariables.forEach((key, value) -> {
                binding.setVariable(key, value);
            });
        }
        
        // 添加上下文信息
        if (userId != null) {
            binding.setVariable("userId", userId);
        }
        if (username != null) {
            binding.setVariable("username", username);
        }
        if (tenantId != null) {
            binding.setVariable("tenantId", tenantId);
        }
        if (requestId != null) {
            binding.setVariable("requestId", requestId);
        }
        if (clientIp != null) {
            binding.setVariable("clientIp", clientIp);
        }
        if (userAgent != null) {
            binding.setVariable("userAgent", userAgent);
        }
        
        // 注入脚本助手工具类
        binding.setVariable("JsonHelper", GroovyScriptHelper.JsonHelper.class);
        binding.setVariable("MathHelper", GroovyScriptHelper.MathHelper.class);
        binding.setVariable("StringHelper", GroovyScriptHelper.StringHelper.class);
        binding.setVariable("DateHelper", GroovyScriptHelper.DateHelper.class);
        binding.setVariable("CollectionHelper", GroovyScriptHelper.CollectionHelper.class);
        binding.setVariable("HttpHelper", GroovyScriptHelper.HttpHelper.class);
        binding.setVariable("DatabaseHelper", GroovyScriptHelper.DatabaseHelper.class);
        binding.setVariable("LogHelper", GroovyScriptHelper.LogHelper.class);
        binding.setVariable("ContextHelper", GroovyScriptHelper.ContextHelper.class);
        
        // 注入数据源
        if (dataSources != null && !dataSources.isEmpty()) {
            dataSources.forEach((name, dataSource) -> {
                binding.setVariable("dataSource_" + name, dataSource);
            });
        }
        
        return binding;
    }

    /**
     * 添加参数
     */
    public GroovyScriptExecutionContext addParameter(String key, Object value) {
        this.parameters.put(key, value);
        return this;
    }

    /**
     * 添加系统变量
     */
    public GroovyScriptExecutionContext addSystemVariable(String key, Object value) {
        this.systemVariables.put(key, value);
        return this;
    }

    /**
     * 添加数据源
     */
    public GroovyScriptExecutionContext addDataSource(String name, DataSource dataSource) {
        this.dataSources.put(name, dataSource);
        return this;
    }
}